package com.javase.多线程.JUC三大辅助类;

import org.junit.jupiter.api.Test;
import sun.awt.AWTAccessor;

import java.util.concurrent.*;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @Auther: liyanhao
 * @Description: CountDownLatch允许一个或者多个线程去等待其他线程完成操作
 * @Date: 2022/5/14 16:15
 * @Version: v1.0
 */
public class CountDownLatchDemo {
    //countDownLatch
    // 六个同学陆续离开教室后值班同学才可以关门
    @Test
    public void TestCountDownLatch() throws InterruptedException {
        CountDownLatch countDownLatch = new CountDownLatch(7);
        for (int i = 0; i < 7; i++) {
            final int a = i;
            new Thread(()->{
                System.out.println("同学"+Thread.currentThread().getName()+"离开了" + "");
                countDownLatch.countDown();
            },i+"").start();
        }
        countDownLatch.await();
        //全部离开后自动唤醒主线程
        System.out.println("全部离开了,现在的计数器为" +
                countDownLatch.getCount());
    }
    //CyclicBarrier
    //栅栏类似于闭锁，它能阻塞一组线程直到某个事件的发生
    public static void main(String[] args) {
        int NUMBER = 7;
        CyclicBarrier cyclicBarrier = new CyclicBarrier(NUMBER, () -> {
            System.out.println("集齐" + NUMBER + "颗龙珠,现在召唤神龙!!!!!!!!!");
        });
        for (int i = 0; i < 7; i++) {
            new Thread(()->{
                System.out.println("集齐第"+Thread.currentThread().getName()+" 颗龙珠");
                try {
                    TimeUnit.SECONDS.sleep(3);
                    cyclicBarrier.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
            },i+"").start();
        }
    }

    //Semaphore     
    //Semaphore（信号量）是用来控制同时访问特定资源的线程数量，通过协调各个线程以保证合理地使用公共资源。
    @Test
    public void TestSemaphore(){
        Semaphore semaphore = new Semaphore(3);
        for (int i = 0; i < 6; i++) {
            new Thread(()->{
                System.out.println(Thread.currentThread().getName()+" 找到车位了");
                try {
                    semaphore.acquire();
                    System.out.println(Thread.currentThread().getName()+" 抢到这位了");
                    TimeUnit.SECONDS.sleep(3);
                } catch (Exception e) {
                    e.printStackTrace();
                }finally {
                    System.out.println(Thread.currentThread().getName()+"溜了溜了");
                }
            },i+"").start();                                                                                                                 
        }
    }


    //线程A、B交替打印
    @Test
    public void TestReentrantLockDemo1(){

    }

    public static void main2(String[] args) {
        ReentrantLockDemoClass reentrantLockDemoClass = new ReentrantLockDemoClass();
        new Thread(()->{
            for (int i = 0; i < 5; i++) {
                try {
                    reentrantLockDemoClass.increment();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"线程A").start();
        new Thread(()->{
            for (int i = 0; i < 5; i++) {
                try {
                    reentrantLockDemoClass.reduce();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"线程B").start();
    }

    //问题: A 线程打印 5 次 A，B 线程打印 10 次 B，C 线程打印 15 次 C,按照
    // 此顺序循环 10 轮==
    public static void main5(String[] args) {
        new Thread(()->{
            ReentrantLockDemoClass2 reentrantLockDemoClass2 = new ReentrantLockDemoClass2();
            for (int i = 0; i < 10; i++) {
                try {
                    reentrantLockDemoClass2.printA();
                    reentrantLockDemoClass2.printB();
                    reentrantLockDemoClass2.printC();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
        }).start();
    }





}
class ReentrantLockDemoClass2{
    private int number = 0;
    private Lock lock = new ReentrantLock();
    private Condition conditionA = lock.newCondition();
    private Condition conditionB= lock.newCondition();
    private Condition conditionC = lock.newCondition();
    public void printA() throws InterruptedException {
        lock.lock();
        while (number != 0) {
            conditionA.await();
        }
        for (int i = 0; i < 5; i++) {
            System.out.println("线程A打印第" + i + "次");
        }
        number++;
        conditionA.signalAll();
        lock.unlock();
    }

    public void printB()throws InterruptedException{
        lock.lock();
        while (number != 1) {
            conditionB.await();
        }
        for (int i = 0; i < 10; i++) {
            System.out.println("线程B打印第" + i + "次");
        }
        number++;
        conditionB.signalAll();
        lock.unlock();
    }
    public void printC()throws InterruptedException{
        lock.lock();
        while (number != 2) {
            conditionC.await();
        }
        for (int i = 0; i < 15; i++) {
            System.out.println("线程C打印第" + i + "次");
        }
        number = 0;
        conditionC.signalAll();
        lock.unlock();
    }

}


//ReentrantLock
class ReentrantLockDemoClass{
    private int number = 0;
    private Lock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();
    public void increment() throws InterruptedException {
        lock.lock();
        try {
            while (number != 0) {
                condition.await();
            }
            number++;
            System.out.println("--------" + Thread.currentThread().getName() + "加一" +
                    "成功----------,值为:" + number);
            condition.signalAll();
        } catch (Exception e) {

        }finally {
            lock.unlock();
        }
    }
    public void reduce() throws InterruptedException {
        lock.lock();
        while (number == 0) {
            condition.await();
        }
        number--;
        System.out.println("--------" + Thread.currentThread().getName() + "减一" +
                "成功----------,值为:" + number);
        condition.signalAll();
        lock.unlock();
    }
}
